package com.tianji.learning.service.impl;

import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningLessonDTO;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static com.tianji.learning.enums.LessonStatus.*;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author 陈宽
 * @since 2025-06-28
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler delayTaskHandler;

    @Override
    public LearningLessonDTO getLearningLesson(Long courseId) {
        Long userId = UserContext.getUser();
        //查询课表数据
        LearningLesson lesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if (ObjectUtils.isEmpty(lesson)) {
            return null;
        }
        //从redis里面得到播放记录
        Map<Long, LearningRecord> allRedisRecord = delayTaskHandler.getAllRedisRecord(lesson.getId());
        //查询课程的播放记录
        List<LearningRecord> list = this.lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getLessonId, lesson.getId())
                .list();
        //当allRedisRecord不为空，就开始填充播放进度
        if (!ObjectUtils.isEmpty(allRedisRecord)) {
            list.forEach(record -> {
                LearningRecord redisRecord = allRedisRecord.get(record.getSectionId());
                if (ObjectUtils.isNotNull(redisRecord)&&ObjectUtils.isNotNull(redisRecord.getMoment())) {
                    record.setMoment(redisRecord.getMoment());
                }
            });
        }
        //装填DTO
        return LearningLessonDTO.of(lesson.getId(), lesson.getLatestSectionId(), list);
    }

    @Override
    @Transactional
    public void submitLearningRecord(LearningRecordFormDTO dto) {
        //根据状态来对视频和考试进行不同的处理
        //对学习记录表进行操作
        Boolean result = dto.getSectionType().equals(SectionType.VIDEO) ? submitVideoRecord(dto) : submitExamRecord(dto);
        if (dto.getDuration()==-1){
            return;
        }
        //对课表进行操作
        handlerLessonRecord(result, dto);
    }

    private void handlerLessonRecord(Boolean result, LearningRecordFormDTO dto) {
        // 1、查询课表数据（已学习小节数、课程ID）
        LearningLesson lesson = this.lessonService.getById(dto.getLessonId());
        AssertUtils.isNotNull(lesson,"课表信息不存在，无法更新数据");

        // 2、查询课程数据，判断是否全部学完所有小节
        boolean allLearnd = false;
        if(result) {
            // 2.1、查询课程数据
            CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            AssertUtils.isNotNull(courseInfo, "课程信息不存在，无法更新数据");

            // 2.2、比较（已完成小节数 + 1 >= 课程总小节数）
            allLearnd = lesson.getLearnedSections() + 1 >= courseInfo.getSectionNum();
        }

        // 更新课表数据
        boolean updateResult = this.lessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId, dto.getSectionId())
                .set(LearningLesson::getLatestLearnTime, dto.getCommitTime())
                //.set(LearningLesson::getLearnedSections, lesson.getLearnedSections() + 1)
                .setSql(result,"learned_sections = learned_sections + 1")
                .set(allLearnd,LearningLesson::getStatus, FINISHED)
                .set(lesson.getStatus() == NOT_BEGIN, LearningLesson::getStatus, LEARNING)
                .eq(LearningLesson::getId, dto.getLessonId())
                .update();

        if(!updateResult){
            throw new DbException("更新课表数据失败");
        }
    }

    private Boolean submitExamRecord(LearningRecordFormDTO dto) {
        //封装数据
        LearningRecord oldRecord = BeanUtils.toBean(dto, LearningRecord.class);
        //给没有数据的字段赋值
        oldRecord.setUserId(UserContext.getUser());
        oldRecord.setFinished(true);
        oldRecord.setFinishTime(dto.getCommitTime());
        //保存
        boolean result = save(oldRecord);
        if ( !result){
            throw new DbException("保存学习记录失败");
        }
        return true;
    }

    private Boolean submitVideoRecord(LearningRecordFormDTO dto) {
        //1.根据小节id和课表id查询学习记录
//        LearningRecord oldRecord = this.lambdaQuery()
//                .eq(LearningRecord::getSectionId, dto.getSectionId())
//                .eq(LearningRecord::getLessonId, dto.getLessonId())
//                .one();
        LearningRecord oldRecord = getOldRecord(dto);
        //2.判空
        //3.如果存在则更新，不存在则新增
        if (ObjectUtils.isNull(oldRecord)) {
            //3.1 新增
            oldRecord = BeanUtils.toBean(dto, LearningRecord.class);
            oldRecord.setUserId(UserContext.getUser());
            boolean save = save(oldRecord);
            if (!save) {
                throw new DbException("保存学习记录失败");
            }
            return false;
        }
        // 4、如果存在，更新学习记录
        // 4.1、判断是否是第一次学完当前小节
        boolean firstFinished = !oldRecord.getFinished() && dto.getMoment() << 1 > dto.getDuration();

        // 4.2、更新学习记录（一定要更新的字段：moment，第一次学完时更新的两个字段：finished、finish_time）
        if(firstFinished){
            boolean updateResult = this.lambdaUpdate()
                    .set(LearningRecord::getMoment, dto.getMoment())
                    .set(LearningRecord::getFinished, true)
                    .set(LearningRecord::getFinishTime, dto.getCommitTime())
                    .eq(LearningRecord::getId, oldRecord.getId())
                    .update();
            if (!updateResult) {
                throw new DbException("更新视频学习记录失败");
            }
            //删除redis缓存
            delayTaskHandler.deleteRedis(oldRecord);
        }else {
            LearningRecord record = BeanUtils.toBean(dto, LearningRecord.class);
            record.setId(oldRecord.getId());
            record.setFinished(oldRecord.getFinished());
            record.setUpdateTime(dto.getCommitTime());
            delayTaskHandler.addDelayTask(record);
            dto.setDuration(-1);
        }
        return firstFinished;

        //判断是否是第一次学完
//        //4 判断状态，如果是已经完成则是第二次播放
//        if (oldRecord.getFinished()) {
//            oldRecord.setMoment(dto.getMoment());
//            oldRecord.setUpdateTime(dto.getCommitTime());
//            boolean update = updateById(oldRecord);
//            if (!update) {
//                throw new DbException("更新学习记录失败");
//            }
//            return false;
//        }
//        //5.更新的时候判断播放进度
//        if (oldRecord.getMoment() *2 >= dto.getDuration() ) {
//            //5.1.如果播放进度已经超过一半就更新为完成
//            oldRecord.setFinished(true);
//            oldRecord.setMoment(dto.getDuration());
//            oldRecord.setFinishTime(dto.getCommitTime());
//            oldRecord.setId(oldRecord.getId())
//            boolean result = this.updateById(oldRecord);
//            if ( !result){
//                throw new DbException("更新学习记录失败");
//            }
//            return true;
//        }
//        //5.2.如果播放进度没有超过一半就更新数据
//        oldRecord.setMoment(dto.getMoment());
//        oldRecord.setUpdateTime(dto.getCommitTime());
//        boolean result = this.updateById(oldRecord);
//        if (!result){
//            throw new DbException("更新学习记录失败");
//        }
//        return false;
    }
    private LearningRecord getOldRecord(LearningRecordFormDTO dto) {
        //1.首先到redis里面查询有没有数据，有则返回
        LearningRecord oldRecord =delayTaskHandler.readRedis(dto.getLessonId(), dto.getSectionId());
        //2.没有则查询数据库
        if (ObjectUtils.isEmpty(oldRecord)){
            oldRecord = this.lambdaQuery()
                    .eq(LearningRecord::getSectionId, dto.getSectionId())
                    .eq(LearningRecord::getLessonId, dto.getLessonId())
                    .one();
            //2.1 然后存到redis里面
            if (!ObjectUtils.isEmpty(oldRecord)){
                delayTaskHandler.writeRedis(oldRecord);
            }
        }
        //3.还没有则返回null
        return oldRecord;
    }

}
